class Cerebro(with_metaclass(MetaParams, object)):
    '''
    参数：
          - `preload``（默认值：``True``）

            是否给策略传递不同的预加载“数据源”

          - `runonce``（默认值：``True``）

            以矢量化模式运行“指标”，以加快整个系统的速度。策略和观察者将始终基于事件运行

          - `live``（默认值：``False``）

            如果没有数据通过数据的“islive”方法报告自己为“live”，但最终用户仍希望以“live”模式运行，则可以将此参数设置为true

            这将同时停用“preload”和“runonce”。它对内存节省方案没有影响。

            以矢量化模式运行“指标”，以加快整个系统的速度。策略和观察者将始终基于事件运行

          - `maxcpus``（默认值：无->所有可用核心）

             同时使用多少个核心进行优化

          - `stdstats``（默认值：``True``）

            如果为True，则会添加默认观察者：Broker（现金和价值）、Trades和BuySell

          - `oldbuysell`` (默认值：``False``)

            如果 ``stdstats`` 为 ``True`` 并且观察者自动添加，此开关控制 ``BuySell`` 观察者的主要行为

            - `False``：使用现代行为，在此行情况下，买入/卖出信号在低/高价格下方/上方绘制，以避免杂乱无章的绘图

            - `True``：使用已弃用的行为，在此行情况下，买入/卖出信号在给定时间的订单执行的平均价格处绘制。当然，这将在 OHLC 条形图或 Cloe 条形图上方，使绘图难以识别。

          - `oldtrades`` (默认值：``False``)

            如果 ``stdstats`` 为 ``True`` 并且观察者自动添加，此开关控制 ``Trades`` 观察者的主要行为

            - `False``：使用现代行为，在此行情况下，所有数据的交易都使用不同的标记绘制

            - `True``：使用旧的交易观察者，它使用相同的标记绘制交易，仅区分它们是正数还是负数

          - `exactbars`` (默认值：``False``)

            默认情况下，每个线中存储的每个值都会保留在内存中

            可能的值：
              - `True`` 或 ``1``：所有“线”对象将减少内存使用量到自动计算的最小周期。

                如果简单移动平均值的周期为 30，则底层数据将始终具有 30 个条形缓冲区，以允许计算简单移动平均值

                - 此设置将停用 ``preload`` 和 ``runonce``
                - 使用此设置还会停用 **绘图**

              - `-1``：策略级别的数据源和指标/操作将在内存中保留所有数据。

                例如：``RSI`` 内部使用指标 ``UpDay`` 进行计算。此子指标将不会在内存中保留所有数据

                - 这允许保持 ``plotting`` 和 ``preloading`` 活动。

                - 将停用 ``runonce``

              - `-2``：策略保留为属性的数据源和指标将在内存中保留所有点。

                例如：``RSI`` 内部使用指标 ``UpDay`` 进行计算。此子指标将不会在内存中保留所有数据

                如果在 ``__init__`` 中定义了类似于 ``a = self.data.close - self.data.high`` 的内容，则 ``a`` 将不会在内存中保留所有数据

                - 这允许保持 ``plotting`` 和 ``preloading`` 活动。

                - 将停用 ``runonce``

          - `objcache`` (默认值：``False``)

            实验性选项，用于实现线对象的缓存并减少它们的数量。例如，UltimateOscillator::

              bp = self.data.close - TrueLow(self.data)
              tr = TrueRange(self.data)  # -> creates another TrueLow(self.data)

            如果这是 ``True``，则 ``TrueRange`` 中的第二个 ``TrueLow(self.data)`` 与 ``bp`` 计算中的那个的签名匹配。它将被重用。

            在某些极端情况下，这可能会使线对象超出其最小周期并破坏事物，因此被禁用。

          - `writer`` (默认值：``False``)

            如果设置为 ``True``，将创建一个默认的 WriterFile，它将打印到 stdout。它将添加到策略中（除了用户代码添加的任何其他 writer）

          - `tradehistory`` (默认值：``False``)

            如果设置为 ``True``，它将激活每个交易中的更新事件日志记录所有策略。这也可以通过策略方法 ``set_tradehistory`` 在每个策略上完成

          - `optdatas`` (默认值：``True``)

            如果 ``True`` 并且正在优化（系统可以 ``preload`` 和使用 ``runonce``），则仅在主进程中执行一次数据预加载以节省时间和资源。

            测试显示，从执行时间为 ``83`` 秒的样本执行移动到执行时间为 ``66`` 秒的样本，速度提高了约 ``20%``

          - `optreturn`` (默认值：``True``)

            如果 ``True``，则优化结果将不是完整的 ``Strategy`` 对象（以及所有 *datas*、*indicators*、*observers* ...），而是具有以下属性的对象（与 ``Strategy`` 相同）：

              - `params``（或 ``p``）策略执行的参数
              - `analyzers`` 策略已执行

            在大多数情况下，只需要 *analyzers* 和使用哪些 *params* 来评估策略的性能。如果需要对生成的值（例如）*indicators* 进行详细分析，请关闭此选项

            测试显示，执行时间提高了 ``13% - 15%``。与 ``optdatas`` 结合使用，总收益增加到优化运行的总速度提高了 ``32%``
            tr = TrueRange(self.data)  # -> 创建另一个 TrueLow(self.data)

            # 如果这是“True”，则“TrueRange”中的第二个“TrueLow(self.data)”与“bp”计算中的那个的签名匹配。它将被重用。

            # 在某些极端情况下，这可能会使线对象超出其最小周期并破坏事物，因此被禁用。

          - “writer”（默认值：“False”）

            如果设置为“True”，将创建一个默认的WriterFile，它将打印到stdout。它将添加到策略中（除了用户代码添加的任何其他writer）

          - “tradehistory”（默认值：“False”）

            如果设置为“True”，它将激活每个交易中的更新事件日志记录所有策略。这也可以通过策略方法“set_tradehistory”在每个策略上完成

          - “optdatas”（默认值：“True”）

            如果“True”并且正在优化（系统可以“preload”和使用“runonce”），则仅在主进程中执行一次数据预加载以节省时间和资源。

            测试显示，从执行时间为“83”秒的样本执行移动到执行时间为“66”秒的样本，速度提高了约“20%”

          - “optreturn”（默认值：“True”）

            如果“True”，则优化结果将不是完整的“Strategy”对象（以及所有*datas*、*indicators*、*observers* ...），而是具有以下属性的对象（与“Strategy”相同）：

              - “params”（或“p”）策略执行的参数
              - “analyzers”策略已执行

            在大多数情况下，只需要*analyzers*和使用哪些*params*来评估策略的性能。如果需要对生成的值（例如）*indicators*进行详细分析，请关闭此选项

            # 测试显示，执行时间提高了“13% - 15%”。与“optdatas”结合使用，总收益增加到优化运行的总速度提高了“32%”

          - “oldsync”（默认值：“False”）

            从版本1.9.0.99开始，多个数据的同步（相同或不同的时间框架）已更改为允许不同长度的数据。

            如果希望使用data0作为系统的主数据的旧行为，则将此参数设置为true

          - “tz”（默认值：“None”）

            为策略添加全局时区。参数“tz”可以是

              - “None”：在这种情况下，策略显示的日期时间将为UTC，这一直是标准行为

              - “pytz”实例。它将被用作这样将UTC时间转换为所选时区

              - “string”。将尝试实例化一个“pytz”实例。

              - “integer”。对于策略，使用与“self.datas”可迭代对象中的相应“data”相同的时区（“0”将使用“data0”的时区）

          - “cheat_on_open”（默认值：“False”）

            策略的“next_open”方法将被调用。这发生在“next”之前，也发生在券商有机会评估订单之前。指标尚未重新计算。这允许发出一个订单，该订单考虑了前一天的指标，但使用“open”价格进行股份计算

            对于cheat_on_open订单执行，还需要调用“cerebro.broker.set_coo(True)”或使用“BackBroker(coo=True)”实例化券商（其中*coo*代表cheat-on-open）或将“broker_coo”参数设置为“True”。除非禁用，否则Cerebro将自动执行它。

          - “broker_coo”（默认值：“True”）

            # 这将自动调用券商的“set_coo”方法，并将其设置为“True”以激活“cheat_on_open”执行。仅在“cheat_on_open”也为“True”时才会执行


    - `quicknotify``（默认值：“False”）

            券商通知会在交付*下一个*价格之前传递。对于回测，这没有任何影响，但对于实时券商，通知可能会在交付条之前很长时间发生。当设置为“True”时，通知将尽快传递（请参见实时提要中的“qcheck”）

            为了兼容性，设置为“False”。可以更改为“True”

    '''


def set_fund_history(self, fund):
    '''
    添加一个订单历史记录，以便在券商中直接执行，以进行性能评估

      - `fund``: 是一个可迭代对象（例如列表、元组、迭代器、生成器），其中每个元素也将是一个可迭代对象（具有长度），具有以下子元素（有两种格式可用）

        ``[datetime，share_value，net asset value]``

        **注意**：必须按datetime升序排序（或产生排序的元素）

        其中：

          - `datetime`` 是一个python ``date/datetime`` 实例或一个格式为YYYY-MM-DD[THH:MM:SS[.us]]的字符串，其中方括号中的元素是可选的
          - `share_value`` 是一个浮点数/整数
          - `net_asset_value`` 是一个浮点数/整数
    '''


def add_order_history(self, orders, notify=True):
    '''
    添加一个订单历史记录，以便在券商中直接执行，以进行性能评估

      - `orders``: 是一个可迭代对象（例如列表、元组、迭代器、生成器），其中每个元素也将是一个可迭代对象（具有长度），具有以下子元素（有两种格式可用）

        ``[datetime，share_value，net asset value]`` 或 ``[datetime，share_value，net asset value，data]``

        **注意**：必须按datetime升序排序（或产生排序的元素）

        其中：

          - `datetime`` 是一个python ``date/datetime`` 实例或一个格式为YYYY-MM-DD[THH:MM:SS[.us]]的字符串，其中方括号中的元素是可选的
          - `share_value`` 是一个浮点数/整数
          - `net_asset_value`` 是一个浮点数/整数
          - `data`` 如果存在，可以采用以下任何值

            - *None* - 第一个数据源将被用作目标
            - *integer* - 使用该索引的数据（在**Cerebro**中插入顺序）
            - *string* - 具有该名称的数据，例如使用``cerebro.addata(data, name=value)``分配的数据，将成为目标

      - `notify`` (默认值：*True*)

        如果为``True``，则将向系统中插入的第一个策略通知根据``orders``中的每个订单创建的人工订单的信息

    **注意**：在描述中隐含的是需要添加一个数据源，该数据源是订单的目标。例如，分析器需要跟踪回报率
    '''


def notify_timer(self, timer, when, *args, **kwargs):
    '''接收计时器通知，其中“timer”是由“add_timer”返回的计时器，“when”是调用时间。 “args”和“kwargs”是传递给“add_timer”的任何其他参数

    实际的“when”时间可能会更晚，但系统可能无法在之前调用计时器。此值是计时器值，而不是系统时间。
    '''


def add_timer(self, when,
              offset=datetime.timedelta(), repeat=datetime.timedelta(),
              weekdays=[], weekcarry=False,
              monthdays=[], monthcarry=True,
              allow=None,
              tzdata=None, strats=False, cheat=False,
              *args, **kwargs):
    '''
    安排一个计时器以调用“notify_timer”

    参数：

      - `when``: 可以是

        - `datetime.time`` 实例（见下文的 ``tzdata``）
        - `bt.timer.SESSION_START`` 引用会话开始
        - `bt.timer.SESSION_END`` 引用会话结束

     - `offset`` 必须是 ``datetime.timedelta`` 实例

       用于偏移值 ``when``。它在与 ``SESSION_START`` 和 ``SESSION_END`` 结合使用时具有有意义的用途，以指示在会话开始后“15分钟”调用计时器。

      - `repeat`` 必须是 ``datetime.timedelta`` 实例

        表示在第一次调用后，进一步调用是否将在相同的会话中以计划的 ``repeat`` delta 调度

        一旦计时器超过会话结束，它将重置为“when”的原始值

      - `weekdays``：一个 **排序的** 可迭代对象，其中包含表示可以实际调用计时器的哪些天（iso 代码，星期一为1，星期日为7）的整数

        如果未指定，则计时器将在所有天都处于活动状态

      - `weekcarry``（默认值：``False``）。如果为 ``True`` 并且未看到工作日（例如交易假期），则计时器将在下一天执行（即使在新的一周中）

      - `monthdays``：一个 **排序的** 可迭代对象，其中包含表示必须执行计时器的每月哪些天的整数。例如，每月的第15天始终如一

        如果未指定，则计时器将在所有天都处于活动状态

      - `monthcarry``（默认值：``True``）。如果未看到该天（周末，交易假期），则计时器将在下一个可用日执行。

      - `allow``（默认值：``None``）。一个回调，它接收一个“datetime.date”实例，并返回如果允许计时器的日期，则返回“True”，否则返回“False”

      - `tzdata`` 可以是 ``None``（默认值），``pytz`` 实例或 ``data feed`` 实例。

        ``None``：``when``按面值解释（即使它不是），这意味着将其处理为UTC，即使它不是

        ``pytz`` 实例：``when``将被解释为在时区实例指定的本地时间中指定

        ``data feed`` 实例：``when``将被解释为在数据提要实例的“tz”参数指定的本地时间中指定。

        **注意**：如果 ``when`` 是 ``SESSION_START`` 或 ``SESSION_END``，并且 ``tzdata`` 是 ``None``，则系统中的第一个*数据提要*（即 ``self.data0``）将用作查找会话时间的参考。

      - `strats``（默认值：``False``）也调用策略的“notify_timer”

      - `cheat``（默认值 ``False``）如果为 ``True``，则在券商有机会评估订单之前将调用计时器。这打开了在会话开始之前基于开盘价发出订单的机会
      - `*args``：任何额外的参数都将传递给“notify_timer”

      - `**kwargs``：任何额外的关键字参数都将传递给“notify_timer”

    返回值：

      - 创建的计时器

    '''


def addtz(self, tz):
    '''
    使用参数“tz”也可以完成此操作

    为策略添加全局时区。参数“tz”可以是以下类型之一：

      - `None``：在这种情况下，策略显示的日期时间将为UTC，这一直是标准行为

      - `pytz`` 实例。它将被用作将UTC时间转换为所选时区的实例

      - `string``。将尝试实例化一个“pytz”实例。

      - `integer``。对于策略，使用与“self.datas”可迭代对象中相应“data”相同的时区（“0”将使用“data0”的时区）

    '''


def addcalendar(self, cal):
    '''添加全局交易日历到系统中。单独的数据提要可能有单独的日历，这些日历将覆盖全局日历

    “cal”可以是“TradingCalendar”的实例，字符串或“pandas_market_calendars”的实例。字符串将被实例化为“PandasMarketCalendar”（需要在系统中安装模块“pandas_market_calendar”）。

    如果传递的是“TradingCalendarBase”的子类（不是实例），则将实例化它
    '''


def add_signal(self, sigtype, sigcls, *sigargs, **sigkwargs):
    '''向系统添加一个信号，稍后将添加到“SignalStrategy”中'''


def signal_strategy(self, stratcls, *args, **kwargs):
    '''添加一个可以接受信号的SignalStrategy子类'''


def signal_concurrent(self, onoff):
    '''如果系统中添加了信号并且“concurrent”值设置为True，则允许并发订单'''


def signal_accumulate(self, onoff):
    '''如果系统中添加了信号并且“accumulate”值设置为True，则允许在已经进入市场的情况下增加头寸'''


def addstore(self, store):
    '''如果不存在，则添加一个“Store”实例'''


def addwriter(self, wrtcls, *args, **kwargs):
    '''将“Writer”类添加到mix中。实例化将在cerebro中的“run”时间完成'''


def addsizer(self, sizercls, *args, **kwargs):
    '''添加一个“Sizer”类（和args），它是添加到cerebro的任何策略的默认sizer'''


def addsizer_byidx(self, idx, sizercls, *args, **kwargs):
    '''按idx添加一个“Sizer”类。此idx是与“addstrategy”返回的idx兼容的引用。只有由“idx”引用的策略将收到此大小'''


def addindicator(self, indcls, *args, **kwargs):
    '''将“Indicator”类添加到mix中。实例化将在传递的策略中的“run”时间完成'''


def addanalyzer(self, ancls, *args, **kwargs):
    '''将“Analyzer”类添加到mix中。实例化将在“run”时间完成'''


def addobserver(self, obscls, *args, **kwargs):
    '''
    将“Observer”类添加到mix中。实例化将在“run”时间完成
    '''


def addobservermulti(self, obscls, *args, **kwargs):
    '''
    将“Observer”类添加到mix中。实例化将在“run”时间完成

    它将每个“data”添加一次。一个用例是观察单个数据的买入/卖出观察器。

    一个反例是CashValue，它观察系统范围的值
    '''


def addstorecb(self, callback):
    '''添加回调以获取将由notify_store方法处理的消息

    回调的签名必须支持以下内容：

      - callback(msg, \*args, \*\*kwargs)

    实际接收到的“msg”，“*args”和“**kwargs”是实现定义的（完全取决于*data/broker/store*），但通常应该期望它们是*可打印的*，以允许接收和实验。
    '''


def notify_store(self, msg, *args, **kwargs):
    '''在cerebro中接收存储通知

    可以在“Cerebro”子类中覆盖此方法

    实际接收到的“msg”，“*args”和“**kwargs”是实现定义的（完全取决于*data/broker/store*），但通常应该期望它们是*可打印的*，以允许接收和实验。
    '''


def adddatacb(self, callback):
    '''添加回调以获取将由notify_data方法处理的消息

    回调的签名必须支持以下内容：

      - callback(data, status, \*args, \*\*kwargs)

    实际接收到的“*args”和“**kwargs”是实现定义的（完全取决于*data/broker/store*），但通常应该期望它们是*可打印的*，以允许接收和实验。
    '''


def notify_data(self, data, status, *args, **kwargs):
    '''在cerebro中接收数据通知

    可以在“Cerebro”子类中重写此方法

    实际接收到的“*args”和“**kwargs”是实现定义的（完全取决于*data/broker/store*），但通常应该期望它们是*可打印的*，以允许接收和实验。
    '''


def adddata(self, data, name=None):
    '''
    将“Data Feed”实例添加到混合中。

    如果“name”不为None，则将其放入“data._name”中，该名称用于装饰/绘图目的。
    '''


def chaindata(self, *args, **kwargs):
    '''
    将多个数据源链接成一个

    如果将名称作为命名参数传递且不为None，则将其放入“data._name”中，该名称用于装饰/绘图目的。

    如果为“None”，则将使用第一个数据的名称
    '''


def rolloverdata(self, *args, **kwargs):
    '''将多个数据源链接成一个

    如果将名称作为命名参数传递且不为None，则将其放入“data._name”中，该名称用于装饰/绘图目的。

    如果为“None”，则将使用第一个数据的名称

    任何其他kwargs都将传递给RollOver类

    '''


def replaydata(self, dataname, name=None, **kwargs):
    '''
    添加要由系统重播的“Data Feed”

    如果“name”不为None，则将其放入“data._name”中，该名称用于装饰/绘图目的。

    任何其他kwargs，如“timeframe”，“compression”，“todate”，这些都受到重播过滤器的支持，将被透明地传递
    '''


def resampledata(self, dataname, name=None, **kwargs):
    '''
    将“Data Feed”添加到系统中以进行重新采样

    如果“name”不为None，则将其放入“data._name”中，该名称用于装饰/绘图目的。

    任何其他kwargs，如“timeframe”，“compression”，“todate”，这些都受到重新采样过滤器的支持，将被透明地传递
    '''


def optcallback(self, cb):
    '''
    将回调函数添加到回调函数列表中，当每个策略运行完毕时，将调用该回调函数

    签名：cb(strategy)
    '''


def optstrategy(self, strategy, *args, **kwargs):
    '''
    将“Strategy”类添加到优化中。实例化将在“run”时间内发生。

    args和kwargs必须是可迭代的，其中包含要检查的值。

    例如：如果策略接受参数“period”，则为了优化，对“optstrategy”的调用如下所示：

      - cerebro.optstrategy(MyStrategy, period=(15, 25))

    这将使用值15和25执行优化。而

      - cerebro.optstrategy(MyStrategy, period=range(15, 25))

    将使用“period”值15->25（25不包括在内，因为Python中的范围是半开放的）

    如果传递了参数但不应进行优化，则调用如下所示：

      - cerebro.optstrategy(MyStrategy, period=(15,))

    请注意，“period”仍然作为可迭代对象传递...只有1个元素

    无论如何，“backtrader”都会尝试识别以下情况：

      - cerebro.optstrategy(MyStrategy, period=15)

    并在可能的情况下创建内部伪可迭代对象
    '''


def addstrategy(self, strategy, *args, **kwargs):
    '''
    将“Strategy”类添加到单次运行的混合中。
    实例化将在“run”时间内发生。

    args和kwargs将按照它们在实例化期间传递给策略。

    返回可以引用其他对象（如sizers）添加的索引
    '''


def setbroker(self, broker):
    '''
    为此策略设置特定的“broker”实例，替换从cerebro继承的实例。
    '''


def getbroker(self):
    '''
    返回券商实例。

    这也可以作为“broker”属性的“property”名称使用
    '''


def plot(self, plotter=None, numfigs=1, iplot=True, start=None, end=None,
         width=16, height=9, dpi=300, tight=True, use=None,
         **kwargs):
    '''
    绘制cerebro中的策略

    如果“plotter”为None，则创建默认的“Plot”实例，并在实例化期间将“kwargs”传递给它。

    “numfigs”将图表分成指定数量的图表，如果希望减少图表密度

    “iplot”：如果为“True”并在“notebook”中运行，则图表将以内联方式显示

    “use”：将其设置为所需matplotlib后端的名称。它将优先于“iplot”

    “start”：策略的日期时间线数组的索引或“datetime.date”，“datetime.datetime”实例，指示绘图的开始

    “end”：策略的日期时间线数组的索引或“datetime.date”，“datetime.datetime”实例，指示绘图的结束

    “width”：保存的图形的英寸

    “height”：保存的图形的英寸

    “dpi”：保存的图形的每英寸点数的质量

    “tight”：仅保存实际内容而不是图形的框架
    '''


def runstop(self):
    '''如果从策略内部或其他任何地方调用，包括其他线程，执行将尽快停止。'''


def run(self, **kwargs):
    '''执行回测的核心方法。传递给它的任何“kwargs”都将影响“Cerebro”实例化时使用的标准参数的值。

    如果“cerebro”没有数据，则该方法将立即退出。

    它具有不同的返回值：

      - 对于无优化：包含使用“addstrategy”添加的Strategy类实例的列表

      - 对于优化：包含使用“addstrategy”添加的Strategy类实例的列表的列表
    '''
